package com.cq.hd.product.validator;

import com.alibaba.fastjson.JSON;
import com.cq.hd.common.constant.Constant;
import com.cq.hd.common.enums.biz.*;
import com.cq.hd.common.response.Throw;
import com.cq.hd.common.utils.LocalDateUtil;
import com.cq.hd.product.api.dto.*;
import com.cq.hd.product.api.dto.ActiveContent;
import com.cq.hd.product.api.dto.ActiveRedPacketSonDto;
import com.cq.hd.product.api.dto.ActiveReleaseDto;
import com.cq.hd.product.api.dto.ActiveStepPriceSonDto;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Optional;

/**
 * 通用活动校验类
 *
 * @author much
 * @since 2024/05/17 22:13
 */
@Slf4j
@Component
public class ActiveCommonValidator extends ActivePublishValidator {

    @Override
    Boolean match(ActiveReleaseDto activeReleaseDto) {
        return true;
    }

    @Override
    void doValidate(ActiveReleaseDto activeReleaseDto) {
        // 活动状态
        validateActiveState(activeReleaseDto);
        // 活动内容
        validateActiveContents(activeReleaseDto);
        // 活动价格
        validateActivePrice(activeReleaseDto);
        // 活动时间
        validateActiveTime(activeReleaseDto);
        // 活动有效期
        validateUseTime(activeReleaseDto);
        // 佣金设置
        validateCommissionSetting(activeReleaseDto);
        // 红包设置
        validateRedPacket(activeReleaseDto);
        // 签到费用
        validateSignInFee(activeReleaseDto);
        // 奖励方式
        validateRewardType(activeReleaseDto);
    }

    private void validateRewardType(ActiveReleaseDto activeReleaseDto) {
        if (!AgentStateEnum.OPEN.getValue().equals(activeReleaseDto.getAgentState())) {
            return;
        }
        if (activeReleaseDto.getRewardType() == null) {
            Throw.isBusinessException("开启分销，奖励方式不能为空");
        }
        if (activeReleaseDto.getRewardType() == 1 && activeReleaseDto.getCommissionRate() == null) {
            Throw.isBusinessException("佣金比例不能为空");
        }
        if (activeReleaseDto.getRewardType() == 2 && activeReleaseDto.getRewardPoints() == null) {
            Throw.isBusinessException("奖励积分未设置");
        }
    }

    // 活动状态
    private void validateActiveState(ActiveReleaseDto activeReleaseDto) {
        if (activeReleaseDto.getActiveState() == null || (activeReleaseDto.getActiveState() != 1 && activeReleaseDto.getActiveState() != 2)) {
            Throw.isBusinessException("活动状态值错误");
        }
    }

    // 活动内容
    private void validateActiveContents(ActiveReleaseDto activeReleaseDto) {
        List<ActiveContent> activeContents = activeReleaseDto.getActiveContents();
        if (CollectionUtils.isEmpty(activeContents)) {
            Throw.isBusinessException("请输入活动内容");
        } else {
            for (ActiveContent activeContent : activeContents) {
                String content = activeContent.getContent();
                if (StringUtils.isEmpty(content)) {
                    log.error("activeContents: {}", JSON.toJSONString(activeContent));
                    Throw.isBusinessException("请输入活动内容");
                }
            }
        }
    }

    // 活动价格
    private void validateActivePrice(ActiveReleaseDto activeReleaseDto) {
        BigDecimal activePrice = activeReleaseDto.getActivePrice();
        if (ZeroStateEnum.NO.getValue().equals(activeReleaseDto.getZeroState())) {
            if (activePrice == null || activePrice.compareTo(new BigDecimal("0.1")) < 0) {
                Throw.isBusinessException("活动价格不能少于0.1元");
            }
        } else {
            activeReleaseDto.setActivePrice(BigDecimal.ZERO);
        }
    }

    // 校验活动时间
    private void validateActiveTime(ActiveReleaseDto activeReleaseDto) {
        // 校验活动时间
        String startTime = activeReleaseDto.getStartTime();
        String endTime = activeReleaseDto.getEndTime();

        if (StringUtils.isEmpty(startTime) || StringUtils.isEmpty(endTime)) {
            Throw.isBusinessException("请设置活动时间");
        }

        LocalDateTime startLocalDateTime = null;
        LocalDateTime endLocalDateTime = null;
        try {
            startLocalDateTime = LocalDateUtil.toLocalDateTime(startTime, Constant.YYYY_MM_DD_HH_MM_SS);
            endLocalDateTime = LocalDateUtil.toLocalDateTime(endTime, Constant.YYYY_MM_DD_HH_MM_SS);
        } catch (Exception e) {
            Throw.isBusinessException("活动时间设置有误");
        }

        LocalDateTime nowLocalDateTime = LocalDateUtil.getNowLocalDateTime();

        // 活动开始时间，不能早于当前时间
        if (nowLocalDateTime.isAfter(startLocalDateTime)) {
            Throw.isBusinessException("活动开始时间不能早于当前时间");
        }

        // 活动开始时间，不能大于活动结束时间
        if (startLocalDateTime.isAfter(endLocalDateTime)) {
            Throw.isBusinessException("活动开始时间不能晚于活动结束时间");
        }

        // 活动时间不能超过360天
        long seconds = LocalDateUtil.getDurationToLocalDateTime(startLocalDateTime, endLocalDateTime).getSeconds();
        if (seconds > 0) {
            long days = (seconds % 60 % 60 % 24) > 0 ? (seconds / 60 / 60 / 24) + 1 : (seconds / 60 / 60 / 24);
            if (days > 360) {
                Throw.isBusinessException("活动时间不能超过360天");
            }
        }
    }

    // 校验活动有效期
    private void validateUseTime(ActiveReleaseDto activeReleaseDto) {
        String validStartTime = activeReleaseDto.getValidStartTime();
        String validEndTime = activeReleaseDto.getValidEndTime();
        if (StringUtils.isEmpty(validStartTime) || StringUtils.isEmpty(validEndTime)) {
            Throw.isBusinessException("请设置使用时间");
        }

        LocalDateTime startLocalDateTime = null;
        LocalDateTime endLocalDateTime = null;
        LocalDateTime validStartLocalDateTime = null;
        LocalDateTime validEndLocalDateTime = null;
        try {
            startLocalDateTime = LocalDateUtil.toLocalDateTime(activeReleaseDto.getStartTime(), Constant.YYYY_MM_DD_HH_MM_SS);
            endLocalDateTime = LocalDateUtil.toLocalDateTime(activeReleaseDto.getEndTime(), Constant.YYYY_MM_DD_HH_MM_SS);
            validStartLocalDateTime = LocalDateUtil.toLocalDateTime(validStartTime, Constant.YYYY_MM_DD_HH_MM_SS);
            validEndLocalDateTime = LocalDateUtil.toLocalDateTime(validEndTime, Constant.YYYY_MM_DD_HH_MM_SS);
        } catch (Exception e) {
            Throw.isBusinessException("使用时间设置有误");
        }

        // 活动有效开始时间，不能大于活动有效结束时间
        if (validStartLocalDateTime.isAfter(validEndLocalDateTime)) {
            Throw.isBusinessException("活动有效开始时间不能晚于活动有效结束时间");
        }

        // 活动结束时间，不能大于活动有效开始时间
        // 有效开始时间不能比活动开始时间早
        if (validStartLocalDateTime.isBefore(startLocalDateTime)) {
            Throw.isBusinessException("活动有效开始时间不能比活动开始时间早");
        }

        // 有效结束时间不能比活动结束时间早
        if (validEndLocalDateTime.isBefore(endLocalDateTime)) {
            Throw.isBusinessException("活动有效结束时间不能比活动结束时间早");
        }

        // 使用时间不能超过360天
        long seconds = LocalDateUtil.getDurationToLocalDateTime(validStartLocalDateTime, validEndLocalDateTime).getSeconds();
        if (seconds > 0) {
            long days = (seconds % 60 % 60 % 24) > 0 ? (seconds / 60 / 60 / 24) + 1 : (seconds / 60 / 60 / 24);
            if (days > 360) {
                Throw.isBusinessException("使用时间不能超过360天");
            }
        }
    }

    // 校验分销设置
    private void validateCommissionSetting(ActiveReleaseDto activeReleaseDto) {
        Integer zeroState = activeReleaseDto.getZeroState();
        BigDecimal activePrice = activeReleaseDto.getActivePrice();

        // 分销开启状态(1-关闭，2-开启)
        Integer agentState = activeReleaseDto.getAgentState();
        if (agentState == null || AgentStateEnum.typeOf(agentState) == null) {
            Throw.isBusinessException("请选择分销开启状态");
        }

        // 实际全核销佣金金额=活动价格*佣金比例=固定佣金金额
        BigDecimal actualCommissionAmt = BigDecimal.ZERO;
        if (AgentStateEnum.OPEN.getValue().equals(agentState)) {
            BigDecimal commissionAmt = activeReleaseDto.getCommissionAmt();
            BigDecimal commissionRate = activeReleaseDto.getCommissionRate();
            // 默认佣金类型：0-无，1-佣金，2-佣金比例
            Integer defaultCommissionType = activeReleaseDto.getDefaultCommissionType();
            String otherEquity = activeReleaseDto.getOtherEquity();

            if (defaultCommissionType == null || DefaultCommissionTypeEnum.typeOf(defaultCommissionType) == null) {
                Throw.isBusinessException("请设置默认佣金类型");
            }

            if (ZeroStateEnum.YES.getValue().equals(zeroState) && !DefaultCommissionTypeEnum.NULL.getValue().equals(defaultCommissionType)) {
                Throw.isBusinessException("零元购活动不能设置佣金");
            }

            if (activePrice.compareTo(new BigDecimal("0.1")) < 0) {
                Throw.isBusinessException("活动价格小于0.1元不支持设置佣金");
            }

            // FIXME 拼团价格校验
            if (PromotionTypeEnum.GROUP_BUY.name().equals(activeReleaseDto.getPromotionType())) {
                GroupBuyActiveReleaseDto groupBuyActiveReleaseDto = (GroupBuyActiveReleaseDto) activeReleaseDto;
                if (groupBuyActiveReleaseDto.getGroupBuyPrice().compareTo(new BigDecimal("0.1")) < 0) {
                    Throw.isBusinessException("拼团价格小于0.1元活动不支持设置佣金");
                }
            }

            if (DefaultCommissionTypeEnum.NULL.getValue().equals(defaultCommissionType)) {
//                if (StringUtils.isEmpty(otherEquity)) {
//                    Throw.isBusinessException("请设置其他权益");
//                }
            } else if (DefaultCommissionTypeEnum.COMMISSION.getValue().equals(defaultCommissionType)) {
                if (commissionAmt == null || commissionAmt.compareTo(BigDecimal.ZERO) <= 0) {
                    Throw.isBusinessException("请设置佣金");
                }

//                // 固定佣金不能大于等于活动价格 TODO
//                if (commissionAmt.compareTo(activePrice) >= 0) {
//                    Throw.isBusinessException("固定金额不能大于等于活动价格");
//                }
//
//                // 实际全核销佣金金额=固定佣金
//                actualCommissionAmt = activeReleaseDto.getCommissionAmt();
            } else if (DefaultCommissionTypeEnum.COMMISSION_RATE.getValue().equals(defaultCommissionType)) {
                if (commissionRate == null || commissionRate.compareTo(BigDecimal.ZERO) <= 0) {
                    Throw.isBusinessException("请设置佣金比例");
                }

                validateCommissionAmt(activeReleaseDto);

//                // 实际全核销佣金金额=活动价格*固定佣金比例 TODO
//                actualCommissionAmt = activePrice.multiply(activeReleaseDto.getCommissionRate()).divide(new BigDecimal("100"), 2, BigDecimal.ROUND_DOWN);
            }

            Integer agentNumState = activeReleaseDto.getAgentNumState();
            if (agentNumState == null || AgentNumStateEnum.typeOf(agentNumState) == null) {
                Throw.isBusinessException("设置推广经纪人类型值错误");
            }

            if (AgentNumStateEnum.NO.getValue().equals(agentNumState) && CollectionUtils.isEmpty(activeReleaseDto.getAgentIds())) {
                Throw.isBusinessException("请选择推广的经纪人");
            }
        }
    }

    // 佣金金额（只留佣金比例，固定佣金废弃）
    private void validateCommissionAmt(ActiveReleaseDto activeReleaseDto) {
        if (!AgentStateEnum.OPEN.getValue().equals(activeReleaseDto.getActiveState())
                || !DefaultCommissionTypeEnum.COMMISSION_RATE.getValue().equals(activeReleaseDto.getDefaultCommissionType())) {
            return;
        }
        // 佣金 <= 活动价 - 红包
        BigDecimal actualCommissionAmt = activeReleaseDto.getActivePrice()
                .multiply(activeReleaseDto.getCommissionRate()).divide(new BigDecimal("100"), 2, RoundingMode.DOWN);

        ActiveRedPacketSonDto activeRedPacket = activeReleaseDto.getActiveRedPacket();
        BigDecimal redPacketAmt = Optional.ofNullable(activeRedPacket)
                .map(ActiveRedPacketSonDto::getFirstRedPacketAmt).orElse(BigDecimal.ZERO);

        BigDecimal subtract = activeReleaseDto.getActivePrice().subtract(redPacketAmt);
        if (actualCommissionAmt.compareTo(subtract) > 0) {
            Throw.isBusinessException("佣金金额不能大于活动价格-红包");
        }
    }

    private void validateRedPacket(ActiveReleaseDto activeReleaseDto) {
        BigDecimal firstRedPacketAmt = BigDecimal.ZERO;
        ActiveRedPacketSonDto activeRedPacket = activeReleaseDto.getActiveRedPacket();
        if (activeRedPacket != null) {
            if (ZeroStateEnum.YES.getValue().equals(activeReleaseDto.getZeroState())) {
                Throw.isBusinessException("0元购活动不能设置红包");
            }

            if (activeReleaseDto.getActivePrice().compareTo(new BigDecimal("1")) < 0) {
                Throw.isBusinessException("活动价小于1元,不能设置红包");
            }

            firstRedPacketAmt = activeRedPacket.getFirstRedPacketAmt();
            if (firstRedPacketAmt == null || firstRedPacketAmt.compareTo(BigDecimal.ZERO) <= 0) {
                Throw.isBusinessException("红包金额必须大于0元");
            }

            if (firstRedPacketAmt.compareTo(new BigDecimal("99999999")) > 0) {
                Throw.isBusinessException("红包金额不能大于99999999元");
            }

            Integer redPacketNum = activeRedPacket.getRedPacketNum();
            if (redPacketNum <= 0) {
                Throw.isBusinessException("红包数量必须大于0个");
            }

            if (redPacketNum > 99999999) {
                Throw.isBusinessException("红包数量不能大于99999999个");
            }

            Integer validDay = activeRedPacket.getValidDay();
            if (validDay <= 0) {
                Throw.isBusinessException("红包有效期必须大于0天");
            }

            if (validDay > 99999999) {
                Throw.isBusinessException("红包有效期不能大于99999999天");
            }

            if (firstRedPacketAmt.compareTo(activeReleaseDto.getActivePrice()) > 0) {
                Throw.isBusinessException("红包金额不能大于活动金额");
            }
        }
    }

    // 校验签到费用
    private void validateSignInFee(ActiveReleaseDto activeReleaseDto) {
        // 没开启报名，没有签到费
        if (activeReleaseDto.getEnrollEnable().equals(0)) {
            return;
        }
        if (activeReleaseDto.getSignInFee() == null
                || activeReleaseDto.getSignInFee().compareTo(BigDecimal.ZERO) == 0) {
            return;
        }
        // 签到费用 <= (活动价格|最低阶梯价)-红包-佣金
        BigDecimal activePrice = activeReleaseDto.getActivePrice();
        if (CollectionUtils.isNotEmpty(activeReleaseDto.getActiveStepPrices())) {
            Optional<BigDecimal> min = activeReleaseDto.getActiveStepPrices().stream()
                    .map(ActiveStepPriceSonDto::getEnrollPrice)
                    .min(BigDecimal::compareTo);
            if (min.isPresent()) {
                activePrice = min.get();
            }
        }
        // 红包
        BigDecimal redPacketAmt = Optional.ofNullable(activeReleaseDto.getActiveRedPacket())
                .map(ActiveRedPacketSonDto::getFirstRedPacketAmt).orElse(BigDecimal.ZERO);

        // 佣金
        BigDecimal actualCommissionAmt = calculateCommissionAmt(activeReleaseDto, activePrice);

        BigDecimal subtract = activePrice.subtract(redPacketAmt)
                .subtract(actualCommissionAmt);

        if (activeReleaseDto.getSignInFee().compareTo(subtract) > 0) {
            Throw.isBusinessException("签到费用不可大于活动价-红包");
        }

        // 如果是拼团，需要校验 签到费 <= 拼团价 - 红包
        if (PromotionTypeEnum.GROUP_BUY.name().equals(activeReleaseDto.getPromotionType())) {
            GroupBuyActiveReleaseDto groupBuyActiveReleaseDto = (GroupBuyActiveReleaseDto) activeReleaseDto;
            actualCommissionAmt = calculateCommissionAmt(activeReleaseDto, groupBuyActiveReleaseDto.getGroupBuyPrice());
            BigDecimal diff = groupBuyActiveReleaseDto.getGroupBuyPrice().subtract(redPacketAmt)
                    .subtract(actualCommissionAmt);
            if (activeReleaseDto.getSignInFee().compareTo(diff) > 0) {
                Throw.isBusinessException("签到费用不可大于拼团价-红包");
            }
        }

    }

    private static BigDecimal calculateCommissionAmt(ActiveReleaseDto activeReleaseDto, BigDecimal activePrice) {
        BigDecimal actualCommissionAmt = BigDecimal.ZERO;
        if (AgentStateEnum.OPEN.getValue().equals(activeReleaseDto.getAgentState())) {
            if (activeReleaseDto.getCommissionAmt() != null) {
                actualCommissionAmt = activeReleaseDto.getCommissionAmt();
            } else if (activeReleaseDto.getCommissionRate() != null) {
                actualCommissionAmt = activePrice.multiply(activeReleaseDto.getCommissionRate())
                        .divide(new BigDecimal("100"), 2, RoundingMode.DOWN);
            }
        }
        return actualCommissionAmt;
    }

}
